﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ProLinq.Toolkit
{
	/// <summary>
	/// Base query provider
	/// </summary>
	public abstract class QueryProvider : IQueryProvider
	{
		public TResult Execute<TResult>(Expression expression)
		{
			if (!expression.Type.Is<TResult>())
			{
				throw new ArgumentException(
					String.Format("{0} is not assignable from {1}", typeof (TResult).Name, expression.Type),
					"expression");
			}

			return (TResult) Execute(expression);
		}

		public IQueryable CreateQuery(Expression expression)
		{
			return this.CreateQueryOfT(expression);
		}

		public virtual IQueryable<TElement> CreateQuery<TElement>(Expression expression)
		{
			return new Query<TElement>(this, expression);
		}

		/// <summary>
		/// When implemented in derived class executes an expression and returns result of expression type or derived type.
		/// </summary>
		/// <param name="expression"></param>
		/// <returns></returns>
		public abstract object Execute(Expression expression);
	}
}